package com.lanyou.esb.cook.proxy.redis.persistent.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import redis.clients.jedis.exceptions.JedisException;

import com.lanyou.esb.cook.proxy.entity.IfAlarm;
import com.lanyou.esb.cook.proxy.redis.persistent.base.ListBasePersistentRedis;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.IfAlarmJedisProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.IfAlarmRepeatJedisProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.IfAlarmRepeatTimesJedisProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.IfAlarmUpdateJedisProxy;

/**
 * 持久化接口告警信息：将REDIS中的接口告警转存到数据中
 *
 * @author Davey.wu
 */
public class IfAlarmPersistentRedis extends ListBasePersistentRedis<IfAlarm> {
	/** Redis操作代理 **/
	private IfAlarmJedisProxy jedisProxy;
	/** 重复告警Redis操作代理 **/
	private IfAlarmRepeatJedisProxy ifAlarmRepeatJedisProxy;
	/** 重复告警更新Redis操作代理 **/
	private IfAlarmUpdateJedisProxy ifAlarmUpdateJedisProxy;
	/** 重复告警次数REDIS操作代理 **/
	private IfAlarmRepeatTimesJedisProxy ifAlarmRepeatTimesJedisProxy;

	private Map<String, Boolean> map = new HashMap<>(this.getBatchAmount());

	public IfAlarmPersistentRedis() {
		// 每3分钟执行一次
		this.setCron("0 0/1 * * * ?");
		this.setName("IfAlarmPersistentRedis");
		this.setGroup("IfAlarmPersistentRedis");
		this.setJobClass(this.getClass());
	}

	/**
	 * 注意：先保存再更新，顺序不能变
	 */
	@Override
	public void persistent() throws Exception {
		// 第一步，保存告警信息
		save();
		// 第二步，更新告警信息
		update();
	}

	/**
	 * 保存告警信息
	 * 
	 * @throws Exception
	 */
	private void save() throws Exception {
		List<IfAlarm> list = new ArrayList<>(this.getBatchAmount());
		// 请空历史数据
		list.clear();
		List<IfAlarm> objects = null;
		Map<String, Boolean> map = new HashMap<>();
		while (true) {
			try {
				objects = jedisProxy.lpop(jedisProxy.getKey(),
						this.getBatchReadSize());
				if (objects == null || objects.isEmpty()) {
					break;
				}
				objects = filter(map, objects);
				list.addAll(objects);
				// 达到批量保存的数目，将数据保存到数据库
				if (list.size() >= this.getBatchAmount()) {
					getService().save(list);
					list.clear();
					continue;
				}
			} catch (Exception e) {
				if (e instanceof JedisException) {
					// e.printStackTrace();
					break;
				}
				// TODO 如果是将字符串转换成对象时出错，继续读后面的数据
				objects = null;
			}
		}
		// 保存剩余的数据
		getService().save(list);
		// 请空历史数据
		list.clear();
	}

	/**
	 * 更新告警信息
	 * 
	 * @throws Exception
	 */
	public void update() throws Exception {
		List<IfAlarm> list = new ArrayList<>(this.getBatchAmount());
		// 请空历史数据
		list.clear();
		// 请空历史数据
		map.clear();
		// 告警列表
		List<IfAlarm> objects = null;
		// 键集合
		List<String> keys = null;
		// 未统计的键集合
		List<String> absentKeys = new ArrayList<>();
		// 重复告警次数键值对
		Map<String, Long> values = null;
		while (true) {
			try {
				absentKeys.clear();
				keys = this.ifAlarmUpdateJedisProxy.lpopAsStr(
						this.ifAlarmUpdateJedisProxy.getKey(),
						this.getBatchReadSize());
				// 没有数据，返回
				if (keys == null || keys.isEmpty()) {
					break;
				}
				for (String key : keys) {
					// 排除重复的更新
					if (heveRepeatKey(key, map)) {
						continue;
					}
					map.put(key, true);
					absentKeys.add(key);
				}
				// 获取告警记录
				objects = this.ifAlarmRepeatJedisProxy.get(absentKeys);
				if (objects == null || objects.isEmpty()) {
					continue;
				}
				keys.clear();
				for (IfAlarm object : objects) {
					keys.add(ifAlarmRepeatTimesJedisProxy.getKey(object.getId()));
				}
				// 获取重复告警次数
				values = this.ifAlarmRepeatTimesJedisProxy.getMap(keys);
				// 无记录，跳过
				if (values == null || values.isEmpty()) {
					continue;
				}
				// 设置重复次数
				for (IfAlarm object : objects) {
					Long value = values.get(ifAlarmRepeatTimesJedisProxy
							.getKey(object.getId()));
					if (value == null) {
						value = 0l;
					}
					object.setRepeat(value.intValue());
				}

				list.addAll(objects);
				// 达到批量保存的数目，将数据保存到数据库
				if (list.size() >= this.getBatchAmount()) {
					getService().update(list);
					list.clear();
					continue;
				}

			} catch (Exception e) {
				// e.printStackTrace();
				if (e instanceof JedisException) {
					// e.printStackTrace();
					break;
				}
				// TODO 如果是将字符串转换成对象时出错，继续读后面的数据
				objects = null;
			}
		}
		// 保存剩余的数据
		getService().update(list);
		// 请空历史数据
		list.clear();
		// 请空历史数据
		map.clear();
	}

	/**
	 * 过滤重复的告警
	 * 
	 * @param map
	 * @param objects
	 * @return
	 */
	private List<IfAlarm> filter(Map<String, Boolean> map, List<IfAlarm> objects) {
		if (objects == null || objects.isEmpty()) {
			return objects;
		}
		String key = "";
		for (int i = objects.size() - 1; i >= 0; i--) {
			key = ifAlarmRepeatJedisProxy.getKeyFromObject(objects.get(i));
			if (map.get(key) != null) {
				objects.remove(i);
			}
			map.putIfAbsent(key, true);
		}
		return objects;
	}

	/**
	 * 判断是否存在重复的键
	 * 
	 * @param key
	 * @param map
	 * @return
	 */
	private boolean heveRepeatKey(String key, Map<String, Boolean> map) {
		if (map.size() == 0) {
			return false;
		}
		if (map.get(key) != null) {
			return true;
		}
		return false;
	}

	@Override
	public IfAlarmJedisProxy getJedisProxy() {
		return jedisProxy;
	}

	public void setJedisProxy(IfAlarmJedisProxy jedisProxy) {
		this.jedisProxy = jedisProxy;
	}

	public IfAlarmRepeatJedisProxy getIfAlarmRepeatJedisProxy() {
		return ifAlarmRepeatJedisProxy;
	}

	public void setIfAlarmRepeatJedisProxy(
			IfAlarmRepeatJedisProxy ifAlarmRepeatJedisProxy) {
		this.ifAlarmRepeatJedisProxy = ifAlarmRepeatJedisProxy;
	}

	public IfAlarmUpdateJedisProxy getIfAlarmUpdateJedisProxy() {
		return ifAlarmUpdateJedisProxy;
	}

	public void setIfAlarmUpdateJedisProxy(
			IfAlarmUpdateJedisProxy ifAlarmUpdateJedisProxy) {
		this.ifAlarmUpdateJedisProxy = ifAlarmUpdateJedisProxy;
	}

	public IfAlarmRepeatTimesJedisProxy getIfAlarmRepeatTimesJedisProxy() {
		return ifAlarmRepeatTimesJedisProxy;
	}

	public void setIfAlarmRepeatTimesJedisProxy(
			IfAlarmRepeatTimesJedisProxy ifAlarmRepeatTimesJedisProxy) {
		this.ifAlarmRepeatTimesJedisProxy = ifAlarmRepeatTimesJedisProxy;
	}

}
